package com.apes.fn.scm.used.server;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.scm.used.model.*;
import com.apes.fn.scm.used.repository.UsedDeliverIncomeTypeRepository;
import com.apes.fn.scm.used.repository.UsedRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.logger.ApesLoggerService;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.MapUtil;
import com.apes.scm.income.model.MoneyIncome;
import com.apes.scm.income.model.MoneyIncomeItem;
import com.apes.scm.income.repository.MoneyIncomeItemRepository;
import com.apes.scm.income.repository.MoneyIncomeRepository;
import com.apes.fn.scm.used.repository.UsedDeliverRepository;
import com.apes.scm.income.service.MoneyIncomeService;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.repository.LocationRepository;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/***
 * 旧件出库
 * 1. 不包含赠品
 * 2. 考虑保险
 */
@Service("usedDeliverService")
public class UsedDeliverService extends DomainService {
    @Autowired
    UsedDeliverRepository usedDeliverRepository;
    @Autowired
    UsedRepository usedRepository;
    @Autowired
    UsedStockService usedStockService;
    @Autowired
    MoneyIncomeRepository moneyIncomeRepository;
    @Autowired
    MoneyIncomeItemRepository moneyIncomeItemRepository;
    @Autowired
    UsedDeliverIncomeTypeRepository usedDeliverIncomeTypeRepository;
    @Autowired
    private MoneyIncomeService moneyIncomeService;
    /***
     * 创建
     */
    public UsedDeliver create(SimpleRequest request) {
        UsedDeliver usedDeliver = request.getO(UsedDeliver.class);
        usedDeliver.computeAmt();
        usedDeliver.setState("create");
        checkItemData(usedDeliver);
        usedDeliver.setInputId(request.getPerson());
        usedDeliver.setInputDate(new Date());
        deliverStock(usedDeliver, -1.00); // 减库存
        return usedDeliverRepository.saveAndFlush(usedDeliver);
    }

    /***
     * 修改
     */
    public UsedDeliver update(SimpleRequest request) {
        isValid(request, usedDeliverRepository);
        UsedDeliver usedDeliver = request.getO(UsedDeliver.class);
        usedDeliver.computeAmt();
        checkItemData(usedDeliver);

        //先还原库存
        deliverStock(usedDeliverRepository.findOne(usedDeliver.getId()), 1.00);
        //然后再减库存
        deliverStock(usedDeliver, -1.00);
        return usedDeliverRepository.saveAndFlush(usedDeliver);
    }


    /***
     * 删除
     */
    public String delete(SimpleRequest request) {
        isValid(request, usedDeliverRepository);
        UsedDeliver usedDeliver = request.getO(UsedDeliver.class);
        usedDeliver.setState("delete");
        usedDeliver.setDeleteId(request.getPerson());
        usedDeliver.setDeleteDate(new Date());
        deliverStock(usedDeliver, 1.00); // 加库存
        usedDeliverRepository.saveAndFlush(usedDeliver);
        return "删除成功！";
    }

    /**
     * 申请
     */
    public UsedDeliver apply(SimpleRequest request) {
        isValid(request, usedDeliverRepository);
        UsedDeliver usedDeliver = request.getO(UsedDeliver.class);
        check(usedDeliver);
        usedDeliver.setInputId(request.getPerson());//申请人
        usedDeliver.setInputDate(new Date());
        usedDeliver.setState("apply");
        //当出库类型为标准出库时，自动审核
        if ("UsedDeliver.usedDeliverType.0".equals(usedDeliver.getUsedDeliverType().getId())) {
            return approve(request);
        }
        return usedDeliverRepository.saveAndFlush(usedDeliver);
//        return null;
    }
    /***
     * 审核
     */
    public UsedDeliver approve(SimpleRequest request) {
        isValid(request, usedDeliverRepository);
        UsedDeliver usedDeliver = request.getO(UsedDeliver.class);
        usedDeliver.setState("done");
        usedDeliver.setApproveId(request.getPerson());
        usedDeliver.setApproveDate(new Date());
        if ("UsedDeliver.usedDeliverType.1".equals(usedDeliver.getUsedDeliverType().getId()) || "UsedDeliver.usedDeliverType.0".equals(usedDeliver.getUsedDeliverType().getId())) {
            writeMoneyIncome(usedDeliver,request); // 写资金收入单
        }
        return usedDeliverRepository.saveAndFlush(usedDeliver);
    }


    /***
     * 退回
     */
    public UsedDeliver returnBack(SimpleRequest request) {
        isValid(request, usedDeliverRepository);
        UsedDeliver usedDeliver = request.getO(UsedDeliver.class);
        usedDeliver.setState("create");
        usedDeliver.setReturnId(request.getPerson());
        usedDeliver.setReturnDate(new Date());
//        deliverStock(usedDeliver, 1.00); // 加库存
        return usedDeliverRepository.saveAndFlush(usedDeliver);
    }

    /**
     * 根据收款方式检查
     * @param usedDeliver
     */
    public void check(UsedDeliver usedDeliver) {
        if (usedDeliver.getUsedDeliverIncomeTypes().size() == 0 && (
                usedDeliver.getUsedDeliverType().getCode().equals("0") ||
                usedDeliver.getUsedDeliverType().getCode().equals("1") /*||
                usedDeliver.getUsedDeliverType().getCode().equals("3") ||
                usedDeliver.getUsedDeliverType().getCode().equals("4")*/
                )) throw new RuntimeException("收款方式不能为空！");
        double sum = 0;
        for (UsedDeliverIncomeType type : usedDeliver.getUsedDeliverIncomeTypes()) {
            sum += type.getMoneyIncome();
        }
        if (sum != usedDeliver.getPriceTotal()) throw new RuntimeException("收入资金总额和销售总金额不匹配");
        if (usedDeliver.getPriceTotal() == 0 && usedDeliver.getUsedDeliverType().getCode().equals("1")) throw new RuntimeException("非标准出库下的销售总金额不能为0！");
    }


    /***
     * 写库存帐(标准出库/保险出库)
     */
    public void deliverStock(UsedDeliver usedDeliver, double uom) {
        for (UsedDeliverItem usedDeliverItem : usedDeliver.getUsedDeliverItems()) {
            usedStockService.setUsedStock(
                    usedDeliverItem.getUsed(),
                    usedDeliver.getLocation(),
                    uom * usedDeliverItem.getQtyDeliver(),
                    usedDeliverItem.getCompany(),
                    !usedDeliver.getDeliverInsurance() // 判断是否保险出库
            );
        }
    }

    /***
     * 数据是否合法
     * @param request
     * @param repository
     */
    private Model isValid(SimpleRequest request, CustomRepository repository) {
        Model oldModel = (Model) repository.findOne((String) request.get("id"));
        if (oldModel == null) throw new RuntimeException("订单【" + request.get("id") + "】在系统中不存在。");
        if (oldModel.getVersion() != (int) request.get("version")) throw new RuntimeException("记录已更新或已删除，请重新提交！");
        return oldModel;
    }


    private void checkItemData(UsedDeliver usedDeliver) {
        usedDeliver.getUsedDeliverItems().stream().forEach(item -> {
            if( item.getQtyDeliver() <= 0 ) throw new RuntimeException("存在出库数量小于等于零的旧件,旧件编码：" + item.getUsed().getId());
        });
    }

    /***
     * 写资金收入单
     */
    private void writeMoneyIncome(UsedDeliver usedDeliver, SimpleRequest request){
        MoneyIncome moneyIncome = new MoneyIncome();
        List<User> userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", usedDeliver.getApproveId().getId()));
        moneyIncome.setCreator(usedDeliver.getApproveId().getId());
        moneyIncome.setApproveUID(usedDeliver.getApproveId());
        // 收入日期
        moneyIncome.setPostDate(usedDeliver.getApproveDate());
        //来源单号
        moneyIncome.setSource(usedDeliver.getId());
        //来源单据类型
        moneyIncome.setSourceBusinessType(usedDeliver.getInnerBusinessType());
        //交款人为旧件出库单的申请人
        moneyIncome.setSourceBusinessTypeName("旧件入库单");
        moneyIncome.setPayer(usedDeliver.getInputId());
        moneyIncome.setCompany(usedDeliver.getDept().getCompany());
        moneyIncome.setState("approve");
        moneyIncome.setPostDate(new Date());
        moneyIncome.setApproveDate(new Date());
        moneyIncome.setDept(usedDeliver.getDept());
        if(usedDeliver.getDept().getProfitCenterId() != null){
            moneyIncome.setProfitCenterId(usedDeliver.getDept().getProfitCenterId());
        } else {
            throw new RuntimeException("当前门店的利润中心为空，无法生成资金收入单");
        }

        // 拼明细
        List<MoneyIncomeItem> moneyIncomeItems = usedDeliver.getUsedDeliverIncomeTypes().stream().map(usedDeliverIncomeType -> {
            MoneyIncomeItem moneyIncomeItem = new MoneyIncomeItem();
            moneyIncomeItem.setAmtReceipt(usedDeliverIncomeType.getAmtReceipt());
//            moneyIncomeItem.setReceivableAmount(usedDeliver.getTotalAmount());//应收金额
            moneyIncomeItem.setPaymentMethodType(usedDeliverIncomeType.getPaymentMethodType());
            moneyIncomeItem.setIncomeAmount(usedDeliverIncomeType.getMoneyIncome());//把收款明细的资金收入赋予资金收入单的收入金额
            moneyIncomeItem.setRemark(usedDeliverIncomeType.getRemark());
            moneyIncomeItem.setAccount(usedDeliverIncomeType.getAccount());
            moneyIncomeItem.setAccountName(usedDeliverIncomeType.getAccountName());
            moneyIncomeItem.setMoneyIncome(moneyIncome);
            return moneyIncomeItem;
        }).collect(Collectors.toList());

        moneyIncome.setMoneyIncomeItems(moneyIncomeItems);
        moneyIncomeService.pushOutboxMsg(moneyIncomeRepository.saveAndFlush(moneyIncome));
        // 创建审核
//        MoneyIncome moneyIncomeTemp = this.invoke("money.income.receipts.save", moneyIncome);
//        moneyIncomeTemp = this.invoke("money.income.receipts.approve", moneyIncomeTemp);
        usedDeliver.setMoneyIncome(moneyIncome);
        SpringManager.getBean(ApesLoggerService.class).sendSynEvent("event:ir.logger.create", MapUtil.mapper(
                "businessType", moneyIncome.getInnerBusinessType(),
                "businessKey", moneyIncome.getInnerBusinessKey(),
                "workPostName",request.getSession() != null ? request.getSession().getAttribute("workPostName", String.class) : null,
                "operate", "旧件出库单审核自动生成", "operator_id", userInfo.isEmpty()?"":userInfo.get(0).getId(),
                "remark", null
        ));
//        sendSynEvent("event:ir.logger.create", mapper(
//                "businessType","CarAccident",
//                "businessKey", carAccident.getId(),
//                "operate", "终止",
//                "workPostName", null,
//                "remark", null,
//                "oaFlag", false,
//                "operator_id",user == null ? null : user.getId()));
    }

    /**
     * 查询的旧件和库存数量
     * @param request
     * @return
     */
    public Page<Used> find(SimpleRequest request) {
        //放大镜的查询条件
        if (!request.getJO().toString().contains("condition")) return null;
        List<JSONObject> filters = request.get("condition");
        //旧件出库的仓库编号
        JSONObject domain = (JSONObject)request.getJO().get("domain");
        String locationId = domain.getJSONArray("filters").getJSONObject(0).get("value").toString();
        for (JSONObject filter : filters) {
            if (filter.getString("field").equals("valid") && filter.getString("value").equals("1")) {
                filter.put("value", true);
            }
        }
        //标准出库只能查询轮胎和蓄电池类的旧件
        List<Used> useds = null;
        if (domain.toString().contains("classify")) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("field", "usedClassifyItems.classify.id");
            jsonObject.put("operator", "IN");
            List<String> values = new ArrayList<>();
            values.add("M01010102001");
            values.add("M01010105001");
            jsonObject.put("value", values);
            filters.add(jsonObject);
            useds = usedRepository.findAll(JpaDsl.toCriteria(filters));
            if (useds.isEmpty())  throw new RuntimeException("标准出库，只能查询轮胎和蓄电池类的旧件，可选择非标准出库!");
        }else {
            useds = usedRepository.findAll(JpaDsl.toCriteria(filters));
        }

        UsedStockService usedStockService = SpringManager.getBean(UsedStockService.class);
        LocationRepository locationRepository = SpringManager.getBean(LocationRepository.class);


        //查询库存账并返回
        useds.forEach(used -> {
            UsedStock stockQty = usedStockService.getStockQty(locationRepository.findOne(locationId), used);
            if (stockQty != null) {
                used.setStockQty(stockQty.getStockQty());
                used.setInsuranceStockQty(stockQty.getInsuranceStockQty());
            }
        });


        // 构建返回值
        List<Used> resultList = new ArrayList<>();
        for (Used used : useds) {
            if (used.getStockQty() + used.getInsuranceStockQty() > 0) {
                resultList.add(used);
            }
        }
        if (resultList.isEmpty())  throw new RuntimeException("查询失败，未查询到对应旧件库存");
        // 标准出库需要存在旧件商品价格
        /*if(domain.toString().contains("classify")){
            Dept dept = SpringManager.getBean(DeptRepository.class).findOne(request.getJO().getJSONObject("conditionModel").getJSONObject("dept").getString("id"));
            resultList = resultList.stream().filter(used -> {
                Map map = MapUtil.mapper(
                        "USED_ID",used.getId(),
                        "COMPANY_ID",dept.getCompany().getId(),
                        "SYS_RQ", new Date(),
                        "conditionStrategyId", "CK01"
                );
                Object obj = this.invoke("condition.execConditionStrategy", map);
                JSONObject result=new JSONObject(MapUtil.mapped(obj));
                return result.getDoubleValue("C001") > 0;
            }).collect(Collectors.toList());
        }
        if (resultList.isEmpty())  throw new RuntimeException("标准出库，有库存无旧件价格文件，请联系采购制定旧件价格文件，或选择非标准出库!");*/
        // 分页
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        int fromIndex = pageable.getPageSize()*pageable.getPageNumber();
        int toIndex = pageable.getPageSize()*(pageable.getPageNumber()+1);
        if(toIndex > resultList.size()) toIndex = resultList.size();
        List<Used> current = resultList.subList(fromIndex,toIndex);
        return new PageImpl<Used>(current, pageable, resultList.size());

    }

    /**
     * 取旧件价格
     * @param request
     * @return
     */
    public double getUsedPrice(SimpleRequest request) {
        Map map = MapUtil.mapper(
                "USED_ID",request.get("usedId").toString(),
                "COMPANY_ID",request.get("companyId").toString(),
                "SYS_RQ", new Date(),
                "conditionStrategyId", "CK01"
        );
        Object obj = this.invoke("condition.execConditionStrategy", map);
        JSONObject result=new JSONObject(MapUtil.mapped(obj));
        return result.getDoubleValue("C001");
    }
}
